﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace IECAS.ERS.Services.Pop3
{
    public static class Pop3Decode
    {
        /// <summary>   
        /// QuotedPrintable编码解码   
        /// </summary>   
        /// <param name="txt">原始文字</param>   
        /// <param name="encode">编码方式</param>   
        /// <returns>解码后信息</returns>   
        public static string DecodeQuotedPrintable(string txt, Encoding encode)
        {
            if (string.IsNullOrEmpty(txt))
            {
                return string.Empty;
            }
            System.IO.MemoryStream _Stream = new System.IO.MemoryStream();
            char[] _CharValue = txt.ToCharArray();
            for (int i = 0; i != _CharValue.Length; i++)
            {
                switch (_CharValue[i])
                {
                    case '=':
                        if (_CharValue[i + 1] == '\r' || _CharValue[i + 1] == '\n')
                        {
                            i += 2;
                        }
                        else
                        {
                            try
                            {
                                _Stream.WriteByte(Convert.ToByte(_CharValue[i + 1].ToString() + _CharValue[i + 2].ToString(), 16));
                                i += 2;
                            }
                            catch
                            {
                                _Stream.WriteByte(Convert.ToByte(_CharValue[i]));
                            }
                        }
                        break;
                    default:
                        _Stream.WriteByte(Convert.ToByte(_CharValue[i]));
                        break;
                }
            }
            return encode.GetString(_Stream.ToArray());
        }

        /// <summary>   
        /// 解码BASE64   
        /// </summary>   
        /// <param name="txt"></param>   
        /// <param name="encode"></param>   
        /// <returns></returns>   
        public static string DecodeBase64(string txt, Encoding encode)
        {
            if (string.IsNullOrEmpty(txt))
            {
                return string.Empty;
            }
            byte[] _ValueBytes = Convert.FromBase64String(txt);
            return encode.GetString(_ValueBytes);
        }

        /// <summary>   
        /// 转换文字里的字符集   
        /// </summary>   
        /// <param name="txt"></param>   
        /// <returns></returns>   
        public static string GetReadText(string txt)
        {
            if (string.IsNullOrEmpty(txt))
            {
                return string.Empty;
            }
            System.Text.RegularExpressions.Regex _Regex = new System.Text.RegularExpressions.Regex(@"(?<=\=\?).*?(\?\=)+");
            System.Text.RegularExpressions.MatchCollection _Collection = _Regex.Matches(txt);
            string _Text = txt;
            foreach (System.Text.RegularExpressions.Match _Match in _Collection)
            {
                string _Value = "=?" + _Match.Value;
                if (_Value[0] == '=')
                {
                    string[] _BaseData = _Value.Split('?');
                    if (_BaseData.Length == 5)
                    {
                        System.Text.Encoding _Coding = System.Text.Encoding.GetEncoding(_BaseData[1]);
                        _Text = _Text.Replace(_Value, _Coding.GetString(Convert.FromBase64String(_BaseData[3])));
                    }
                }
                else
                {
                }
            }
            return _Text;
        }

        /// <summary>   
        /// 获取类型（正则）   
        /// </summary>   
        /// <param name="mailContent">原始文字</param>   
        /// <param name="typeTxt">前文字</param>   
        /// <param name="end">结束文字</param>   
        /// <returns>符合的记录</returns>   
        public static string GetTextType(string mailContent, string typeTxt, string end)
        {
            if (string.IsNullOrEmpty(mailContent) || string.IsNullOrEmpty(typeTxt) || end == null)
            {
                return string.Empty;
            }
            System.Text.RegularExpressions.Regex _Regex = new System.Text.RegularExpressions.Regex(@"(?<=" + typeTxt + ").*?(" + end + ")+");
            System.Text.RegularExpressions.MatchCollection _Collection = _Regex.Matches(mailContent);
            if (_Collection.Count == 0)
            {
                return "";
            }
            return _Collection[0].Value;
        }

        public static string GetSubstring(string mailContent, string start, string end)
        {
            if (string.IsNullOrEmpty(mailContent))
            {
                return string.Empty;
            }
            int beginIndex = mailContent.IndexOf(start);
            if (beginIndex == -1)
            {
                return string.Empty;
            }
            int endIndex = mailContent.IndexOf(end, beginIndex + start.Length);
            if (endIndex == -1)
            {
                return string.Empty;
            }
            return mailContent.Substring(beginIndex + start.Length, endIndex - beginIndex + end.Length - start.Length);
        }

        public static string RemoveEnter(string source)
        {
            if (string.IsNullOrEmpty(source))
            {
                return string.Empty;
            }
            return source.Replace(EmailDefine.EnterSign, string.Empty);
        }

        public static string RemoveTab(string source)
        {
            if (string.IsNullOrEmpty(source))
            {
                return string.Empty;
            }
            return source.Replace(EmailDefine.TabSign, string.Empty);
        }
    }

    public class EmailDefine
    {
        public static string SplitSign = ":";
        public static string EmailAddressSign = ",";
        public static string EnterSign = "\r\n";
        public static string SpaceSign = " ";
        public static string TabSign = "    ";
    }


    /// <summary>
    /// DLM: Stores the From:, To:, Subject:, body and attachments
    /// within an email. Binary attachments are Base64-decoded
    /// </summary>
    public class Pop3Message
    {
        /// <summary>
        /// 传进来的ID，用于对比
        /// </summary>
        public string Id { get; set; }
        public Pop3MessageHeader Header
        {
            get;
            private set;
        }
        public List<Pop3MessageContent> ContentList
        {
            get;
            internal set;
        }
        public List<Pop3MessageAttachment> AttachmentList
        {
            get;
            internal set;
        }

        private void LoadEmail(string mailContent)
        {
            string headerContent = GetHeaderText(mailContent);
            string bodyContent = GetBodyText(mailContent);
            Header = new Pop3MessageHeader(headerContent);
            //解析数据
            GetMailBody(bodyContent);
            mailContent = null;
            headerContent = null;
            bodyContent = null;
        }

        public Pop3Message(string id, string emailContent)
        {
            Id = id;
            ContentList = new List<Pop3MessageContent>();
            AttachmentList = new List<Pop3MessageAttachment>();
            LoadEmail(emailContent);
        }

        #region 获取邮件正文 和 附件

        public string GetHeaderText(string mailContent)
        {
            if (string.IsNullOrEmpty(mailContent))
            {
                return null;
            }
            int startIndex = mailContent.IndexOf(EmailMiniDefine.ContentType, 0);
            if (startIndex != -1)
            {
                return mailContent.Substring(0, startIndex);
            }
            else
            {
                return mailContent;
            }
        }

        public string GetBodyText(string mailContent)
        {
            if (string.IsNullOrEmpty(mailContent))
            {
                return null;
            }
            int startIndex = mailContent.IndexOf(EmailMiniDefine.ContentType, 0);
            if (startIndex != -1)
            {
                return mailContent.Substring(startIndex, mailContent.Length - startIndex);
            }
            return null;
        }
        /// <summary>   
        /// 获取文字主体   
        /// </summary>   
        /// <param name="mailContent"></param>   
        /// <returns></returns>   
        public void GetMailBody(string mailContent)
        {
            string _ConvertType = Pop3Decode.GetTextType(mailContent, "\r\nContent-Type: ", ";");
            if (_ConvertType.Length == 0)
            {
                _ConvertType = Pop3Decode.GetTextType(mailContent, "\r\nContent-Type: ", "\r");
            }
            int _StarIndex = -1;
            int _EndIndex = -1;
            string _ReturnText = "";
            string _Transfer = "";
            string _Boundary = "";
            string _EncodingName = Pop3Decode.GetTextType(mailContent, "charset=", "\r").Replace("\r", "");
            System.Text.Encoding _Encoding = System.Text.Encoding.Default;
            if (_EncodingName != "")
            {
                _Encoding = System.Text.Encoding.GetEncoding(_EncodingName);
            }
            switch (_ConvertType)
            {
                case "text/html;":
                    _Transfer = Pop3Decode.GetTextType(mailContent, "\r\nContent-Transfer-Encoding: ", "\r\n").Trim();
                    _StarIndex = mailContent.IndexOf("\r\n\r\n");
                    if (_StarIndex != -1) _ReturnText = mailContent.Substring(_StarIndex, mailContent.Length - _StarIndex);
                    switch (_Transfer)
                    {
                        case "8bit":

                            break;
                        case "quoted-printable":
                            _ReturnText = Pop3Decode.DecodeQuotedPrintable(_ReturnText, _Encoding);
                            break;
                        case "base64":
                            _ReturnText = Pop3Decode.DecodeBase64(_ReturnText, _Encoding);
                            break;
                    }
                    ContentList.Add(new Pop3MessageContent(enumPop3MessageType.Html, _ReturnText));
                    //MailTable.Rows.Add(new object[] { "text/html", _ReturnText });
                    break;
                case "text/plain;":
                    _Transfer = Pop3Decode.GetTextType(mailContent, "\r\nContent-Transfer-Encoding: ", "\r\n").Trim();

                    string disType = Pop3Decode.GetTextType(mailContent, "\r\nContent-Disposition:", ";");
                    //attachment; filename="=?gbk?B?uaTX98jV1r4udHh0?="
                    if (disType == null || disType.IndexOf("attachment") == -1)
                    {
                        _StarIndex = mailContent.IndexOf("\r\n\r\n");
                        if (_StarIndex != -1) _ReturnText = mailContent.Substring(_StarIndex, mailContent.Length - _StarIndex);
                        switch (_Transfer)
                        {
                            case "8bit":

                                break;
                            case "quoted-printable":
                                _ReturnText = Pop3Decode.DecodeQuotedPrintable(_ReturnText, _Encoding);
                                break;
                            case "base64":
                                _ReturnText = Pop3Decode.DecodeBase64(_ReturnText, _Encoding);
                                break;
                        }
                        ContentList.Add(new Pop3MessageContent(enumPop3MessageType.Text, _ReturnText));
                    }
                    else
                    {
                        _StarIndex = mailContent.IndexOf("\r\n\r\n");
                        if (_StarIndex != -1) _ReturnText = mailContent.Substring(_StarIndex, mailContent.Length - _StarIndex);
                        _Transfer = Pop3Decode.GetTextType(mailContent, "\r\nContent-Transfer-Encoding: ", "\r\n").Trim();
                        string _Name = Pop3Decode.GetTextType(mailContent, "filename=\"", "\"").Replace("\"", "");
                        _Name = Pop3Decode.GetReadText(_Name);
                        byte[] _FileBytes = new byte[0];
                        switch (_Transfer)
                        {
                            case "base64":
                                _FileBytes = Convert.FromBase64String(_ReturnText);
                                break;
                        }
                        AttachmentList.Add(new Pop3MessageAttachment(_Name, _FileBytes));
                    }
                    //MailTable.Rows.Add(new object[] { "text/plain", _ReturnText });
                    break;
                case "multipart/alternative;":
                    _Boundary = Pop3Decode.GetTextType(mailContent, "boundary=\"", "\"").Replace("\"", "");
                    _StarIndex = mailContent.IndexOf("--" + _Boundary + "\r\n");
                    if (_StarIndex == -1) return;
                    while (true)
                    {
                        _EndIndex = mailContent.IndexOf("--" + _Boundary, _StarIndex + _Boundary.Length);
                        if (_EndIndex == -1) break;
                        GetMailBody(mailContent.Substring(_StarIndex, _EndIndex - _StarIndex));
                        _StarIndex = _EndIndex;
                    }
                    break;
                case "multipart/mixed;":
                    _Boundary = Pop3Decode.GetTextType(mailContent, "boundary=\"", "\"").Replace("\"", "");
                    _StarIndex = mailContent.IndexOf("--" + _Boundary + "\r\n");
                    if (_StarIndex == -1) return;
                    while (true)
                    {
                        _EndIndex = mailContent.IndexOf("--" + _Boundary, _StarIndex + _Boundary.Length);
                        if (_EndIndex == -1) break;
                        GetMailBody(mailContent.Substring(_StarIndex, _EndIndex - _StarIndex));
                        _StarIndex = _EndIndex;
                    }
                    break;
                default:
                    if (_ConvertType.IndexOf("application/") == 0)
                    {
                        _StarIndex = mailContent.IndexOf("\r\n\r\n");
                        if (_StarIndex != -1) _ReturnText = mailContent.Substring(_StarIndex, mailContent.Length - _StarIndex);
                        _Transfer = Pop3Decode.GetTextType(mailContent, "\r\nContent-Transfer-Encoding: ", "\r\n").Trim();
                        string _Name = Pop3Decode.GetTextType(mailContent, "filename=\"", "\"").Replace("\"", "");
                        _Name = Pop3Decode.GetReadText(_Name);
                        byte[] _FileBytes = new byte[0];
                        switch (_Transfer)
                        {
                            case "base64":
                                _FileBytes = Convert.FromBase64String(_ReturnText);
                                break;
                        }
                        AttachmentList.Add(new Pop3MessageAttachment(_Name, _FileBytes));
                        //MailTable.Rows.Add(new object[] { "application/octet-stream", _FileBytes, _Name });
                    }
                    break;
            }
        }
        
        public class Pop3MessageContent
        {
            public Pop3MessageContent()
            {
            }

            public Pop3MessageContent(enumPop3MessageType type, string content)
            {
                Type = type;
                Content = content;
            }

            public enumPop3MessageType Type
            {
                get;
                internal set;
            }

            public string Content
            {
                get;
                internal set;
            }
        }

        public enum enumPop3MessageType
        {
            Text = 1,
            Html = 2
        }

        public class Pop3MessageAttachment
        {
            public Pop3MessageAttachment(string fileName, byte[] fileContent)
            {
                FileName = fileName;
                FileContent = fileContent;
            }
            public string FileName { get; internal set; }
            public byte[] FileContent { get; internal set; }

            public bool Save(string path)
            {
                if (FileContent == null || FileContent.Length == 0)
                {
                    return false;
                }
                if (string.IsNullOrEmpty(path))
                {
                    path = System.AppDomain.CurrentDomain.BaseDirectory;
                }
                string fileName = null;
                if (path[path.Length - 1] != '\\')
                {
                    fileName = path + "\\" + FileName;
                }
                else
                {
                    fileName = path + FileName;
                }
                try
                {
                    File.WriteAllBytes(fileName, FileContent);
                }
                catch (Exception ex)
                {
                    return false;
                }
                return true;
            }
        }

        public class Pop3MessageHeader
        {
            public Pop3MessageHeader(string headerContent)
            {
                ParseHeader(headerContent);
            }

            public string Received
            {
                get;
                private set;
            }

            /// <summary>
            /// 对方发送时间
            /// </summary>
            public DateTime Date
            {
                get;
                private set;
            }

            public string From
            {
                get;
                private set;
            }

            public string[] To
            {
                get;
                private set;
            }

            public string[] Cc
            {
                get;
                private set;
            }

            public string MessageID
            {
                get;
                private set;
            }

            public string Subject
            {
                get;
                private set;
            }

            #region 获取邮件头

            public void ParseHeader(string headerContent)
            {
                Received = GetReceived(headerContent);
                Date = GetDate(headerContent);
                From = GetFrom(headerContent);
                To = GetTo(headerContent);
                Cc = GetCc(headerContent);
                MessageID = GetMessageId(headerContent);
                Subject = GetSubject(headerContent);
            }

            private string GetReceived(string headerContent)
            {
                if (string.IsNullOrEmpty(headerContent))
                {
                    return string.Empty;
                }
                string retStr = Pop3Decode.GetTextType(headerContent, EmailMiniDefine.Received + EmailDefine.SplitSign, EmailDefine.EnterSign);
                return Pop3Decode.RemoveEnter(retStr);
            }
            public static string GetFrom(string headerContent)
            {
                if (string.IsNullOrEmpty(headerContent))
                {
                    return string.Empty;
                }
                string from = Pop3Decode.GetTextType(headerContent, EmailDefine.EnterSign + EmailMiniDefine.From + EmailDefine.SplitSign, EmailDefine.EnterSign);
                if (string.IsNullOrEmpty(from))
                {
                    return string.Empty;
                }
                from = Pop3Decode.RemoveEnter(from);
                return Pop3Decode.GetReadText(from);
            }

            public static string[] GetTo(string headerContent)
            {
                if (string.IsNullOrEmpty(headerContent))
                {
                    return new string[] { };
                }
                string tos = Pop3Decode.GetTextType(headerContent, EmailDefine.EnterSign + EmailMiniDefine.To + EmailDefine.SplitSign, "[^,]" + EmailDefine.EnterSign);
                if (string.IsNullOrEmpty(tos))
                {
                    return new string[] { };
                }
                tos = Pop3Decode.GetReadText(tos);
                tos = Pop3Decode.RemoveEnter(tos);
                string[] toArrays = tos.Split(new string[] { EmailDefine.EmailAddressSign }, StringSplitOptions.None);
                return toArrays;
            }

            public static string[] GetCc(string headerContent)
            {
                if (string.IsNullOrEmpty(headerContent))
                {
                    return new string[] { };
                }
                //,
                string tos = Pop3Decode.GetTextType(headerContent, EmailDefine.EnterSign + EmailMiniDefine.Cc + EmailDefine.SplitSign, "[^,]" + EmailDefine.EnterSign);
                if (string.IsNullOrEmpty(tos))
                {
                    return new string[] { };
                }
                tos = Pop3Decode.GetReadText(tos);
                if (string.IsNullOrEmpty(tos))
                {
                    return new string[] { };
                }
                else
                {
                    tos = tos.Replace("\r\n", "");
                    tos = tos.Replace("\t", "");
                }
                string[] toArrays = tos.Split(new string[] { EmailDefine.EmailAddressSign }, StringSplitOptions.None);
                return toArrays;
            }

            public static string GetMessageId(string headerContent)
            {
                if (string.IsNullOrEmpty(headerContent))
                {
                    return string.Empty;
                }
                string retStr = Pop3Decode.GetTextType(headerContent, EmailDefine.EnterSign + EmailMiniDefine.MessageID + EmailDefine.SplitSign, EmailDefine.EnterSign);
                return Pop3Decode.RemoveEnter(retStr);
            }

            public static DateTime GetDate(string headerContent)
            {
                if (string.IsNullOrEmpty(headerContent))
                {
                    return DateTime.Now;
                }
                try
                {
                    string date = Pop3Decode.GetTextType(headerContent, EmailDefine.EnterSign + EmailMiniDefine.Date + EmailDefine.SplitSign, EmailDefine.EnterSign);
                    if (string.IsNullOrEmpty(date))
                    {
                        return DateTime.Now;
                    }
                    date = date.Replace(EmailDefine.EnterSign, string.Empty);
                    int pos = date.IndexOf("+");
                    if (pos != -1)
                    {
                        date = date.Substring(0, pos);
                        date = date.Trim();
                    }
                    return Convert.ToDateTime(date);
                }
                catch (Exception ex)
                {
                    return DateTime.Now;
                }
            }

            public static string GetSubject(string headerContent)
            {
                if (string.IsNullOrEmpty(headerContent))
                {
                    return string.Empty;
                }
                string subject = Pop3Decode.GetTextType(headerContent, EmailDefine.EnterSign + EmailMiniDefine.Subject + EmailDefine.SplitSign, EmailDefine.EnterSign);
                string retStr = Pop3Decode.GetReadText(subject);
                return Pop3Decode.RemoveEnter(retStr);
            }
            #endregion
        }

        public class EmailMiniDefine
        {
            /// <summary>
            /// 接收自
            /// </summary>
            public static string Received = "Received";
            /// <summary>
            /// 接收日期
            /// </summary>
            public static string Date = "Date";
            /// <summary>
            /// 发件人
            /// </summary>
            public static string From = "From";
            /// <summary>
            /// 收件人
            /// </summary>
            public static string To = "To";
            /// <summary>
            /// 抄送
            /// </summary>
            public static string Cc = "Cc";
            /// <summary>
            /// 信息唯一标志
            /// </summary>
            public static string MessageID = "Message-ID";
            /// <summary>
            /// 标题
            /// </summary>
            public static string Subject = "Subject";
            /// <summary>
            /// 内容类型
            /// </summary>
            public static string ContentType = "Content-Type";
            /// <summary>
            /// 编码，发送编码base64
            /// </summary>
            public static string ContentTransferEncoding = "Content-Transfer-Encoding";
            /// <summary>
            /// 编码：显示编码
            /// </summary>
            public static string ContentCharSet = "charset";
            /// <summary>
            /// 文本类型attachment代表附件
            /// </summary>
            public static string ContentDisposition = "Content-Disposition";
            public static string ContentDescription = "Content-Description";
            /// <summary>
            /// 名称
            /// </summary>
            public static string Name = "name";
            /// <summary>
            /// 附件名称
            /// </summary>
            public static string FileName = "filename";
        }
        #endregion
    }
}
